iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

Built-in Delegation Pattern

在 Kotlin 中,delegation pattern 已經被內建為語言的一部分,所以開發時可以以更簡潔的方式實作委託模式。Kotlin 提供了 by 關鍵字,可以容易地將某個介面的實作委託給另一個對象。

以下是使用 Kotlin 委託模式的基本步驟和範例

1.定義介面

interface SoundBehavior {
    fun makeSound()
}

2.實作接口

class CatSound : SoundBehavior {
    override fun makeSound() {
        println("Meow!")
    }
}

class DogSound : SoundBehavior {
    override fun makeSound() {
        println("Woof!")
    }
}

使用委任

這裡,Animal 類別不直接實作 SoundBehavior 接口,而是將實作委託給另一個 SoundBehavior 物件。


class Animal(soundBehavior: SoundBehavior) : SoundBehavior by soundBehavior
如此一來,當呼叫 Animal 的 makeSound() 方法時,實際上是呼叫被委託物件的方法。

除了上述基本的委託外,Kotlin 還提供了一些內建的委託功能,例如 Lazy, Observable 等,這在前幾天的章節有提到。

Android 開發上的應用

在 Android 開發中,Kotlin 的委託模式也是非常實用的。以下是一些常見的使用情境:

View Binding

在 Android 的 View Binding 與 Kotlin 合作時,可以使用委託模式來簡化程式碼。例如,如果你有一個名為 ActivityMainBinding 的綁定類別,你可以這樣使用:

class MainActivity : AppCompatActivity() {
    private val binding by viewBinding(ActivityMainBinding::inflate)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        
        binding.textView.text = "Hello, Kotlin Delegates!"
    }
}

viewBinding 是一個定義好的擴展屬性,它將 View Binding 的初始化與清理操作委託給了 ActivityMainBinding::inflate 方法。

DataStore

使用委託來簡化 DataStore<Preferences> 的讀取和寫入操作。例如:


class UserPreferences(context: Context) {
    private val dataStore: DataStore<Preferences> = context.createDataStore("user_prefs")

    // 委託屬性
    var usernameFlow: Flow<String?> = dataStore.data.map { it[USERNAME_KEY] }
    var ageFlow: Flow<Int?> = dataStore.data.map { it[AGE_KEY] }

    suspend fun saveUsername(username: String) {
        dataStore.edit { preferences ->
            preferences[USERNAME_KEY] = username
        }
    }

    suspend fun saveAge(age: Int) {
        dataStore.edit { preferences ->
            preferences[AGE_KEY] = age
        }
    }

    companion object {
        val USERNAME_KEY = preferencesKey<String>("username")
        val AGE_KEY = preferencesKey<Int>("age")
    }
}

ViewModel & LiveData

使用 Kotlin 的委託模式與 Android Architecture Components 一同工作時,可以大幅簡化程式碼。例如,使用委託模式簡化 LiveData 的觀察:

class MainActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        viewModel.myLiveData.observe(this) { data ->
            // 更新 UI
        }
    }
}

Navigation Component 的 Safe Args

使用 Navigation Component 的 Safe Args 插件時,也可以利用 Kotlin 的委託模式。例如:


class DetailFragment : Fragment(R.layout.fragment_detail) {
    val args: DetailFragmentArgs by navArgs()
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val itemId = args.itemId
        //...
    }
}

Dagger 或 Hilt 的注入 (Dependency Injection)

這些只是 Kotlin 委託模式在 Android 開發中應用的一些例子。實際上,隨著社群的發展,還有很多其他的工具和框架利用了 Kotlin 的這一特性,讓 Android 開發變得更加簡潔和高效。

後端開發上的應用

Ktor 的 Features

Ktor 是一個 Kotlin 撰寫的輕量級後端框架。在 Ktor 中,features 可以被認為是一些增加功能的插件,而許多 features 都可以透過委託模式進行簡單地設定:


install(StatusPages) {
    exception<Throwable> { cause ->
        call.respond(HttpStatusCode.InternalServerError, cause.localizedMessage)
    }
}

在上面的範例中,StatusPages 是一個 Ktor 的 feature,它允許我們定義如何處理特定的異常或錯誤狀況。

Spring Boot 與 Kotlin

使用 Spring Boot 和 Kotlin 時,我們可以利用委託模式簡化某些設定或操作,例如應用設定的載入:


@ConfigurationProperties(prefix = "app")
class AppProperties {
    var name: String by Delegates.notNull()
    var version: String? = null
}

這裡,Delegates.notNull() 確保了 name 屬性在使用前一定被初始化,否則會拋出異常。

資料庫存取層 (DAO) 的封裝

若使用像是 Exposed 這種 Kotlin 原生的資料庫框架,你可能會選擇封裝 DAO 層。這樣的情況下,委託模式能幫助你將具體的實作隱藏起來,僅暴露必要的接口:


class UserService(private val dao: UserDao) : UserDao by dao {
    // 你可以在這裡加入其他的業務邏輯或方法
}

這裡,UserService 將 UserDao 的所有方法都委託給了 dao 物件,但同時你可以在 UserService 中加入其他的邏輯或方法。

在後端開發中,委託模式通常用於封裝或簡化常見的任務,並提供更大的彈性。藉由將特定的實作或邏輯委託給其他對象,可以使得系統更容易擴展和維護。

每日一推 G(I)-DLE

今日播放 TomBoy 的 stage mix

Yes


上一篇
D28: Kotlin 集合的效率 - 利用複合高階函式減少操作
下一篇
D30: Effective Kotlin 這本書與 Idiomatic Kotlin
系列文
讓 Kotlin 程式碼更道地 - 談 Effective Kotlin 與相關的 Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言